/*
 * @(#)ConfigurationLoaderListener.java $version 2010. 8. 11
 *
 * Copyright 2007-2010 NHN Corp. All rights Reserved. 
 * NHN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.nhncorp.usf.core.servlet;


import java.io.IOException;
import java.util.List;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import com.nhncorp.lucy.common.config.ConfigurationLoader;
import com.nhncorp.lucy.common.config.model.PlugInInfo;
import com.nhncorp.lucy.common.loader.LoaderException;
import com.nhncorp.lucy.common.plugin.PlugInException;
import com.nhncorp.usf.core.config.ConfigurationBuilder;

/**
 * {@link ConfigurationLoader}의 초기화/소멸을 위한 {@link ServletContextListener}
 * 아래 순서대로 수행한다.
 * <ul>
 * <li>{@link ConfigurationLoader}를 통해 프레임웍의 초기화/소멸</li>
 * </ul>
 * 
 * @author Web Platform Development Team
 */
public class ConfigurationLoaderListener implements ServletContextListener {
	
	/** The log. */
	static Log log = LogFactory.getLog(ConfigurationLoader.class);

	/** The Constant CONFIGURATION_LOCATION_PARAM. */
	public static final String CONFIGURATION_LOCATION_PARAM = "configurationLocation";
	
	/** The configuration loader. */
	private ConfigurationLoader configurationLoader;

	/**
	 * {@link ConfigurationLoader}를 초기화한다.
	 * 
	 * @param event ServletContextEvent
	 */
	public void contextInitialized(ServletContextEvent event) {
		// ServletContext 설정.
		ServletContextHolder.set(event.getServletContext());

		// configuration path 추출
		String configurationLocation = event.getServletContext().getInitParameter(CONFIGURATION_LOCATION_PARAM);

		// configuration, local, plugin 초기화
		configurationLoader = new ConfigurationLoader();
		configurationLoader.addPreConfigurationAware(new ConfigurationBuilder());
		try {
			configurationLoader.initialize(configurationLocation, getInternalConfigurations());
		} catch (PlugInException pe) {
			if (checkFailOnExit(configurationLoader, pe)) {
				// tomcat을 종료한다.
				log.info("The failOnExit option is true, the tomcat process will be stopped!");
				System.exit(1);
			}
		} catch (LoaderException e) {
			configurationLoader.destroy();
			throw e;
		}	
	}

	/**
	 * failOnExit 옵션을 체크한다.
	 * 
	 * @param configLoader the config loader
	 * @param pie the pie
	 * 
	 * @return true, if successful
	 */
	private boolean checkFailOnExit(ConfigurationLoader configLoader, Exception pie) {
		if (pie instanceof PlugInException) {
			PlugInException plugInException = (PlugInException) pie;
			List<PlugInInfo> plugInInfos = configLoader.getConfiguration().getPlugInInfos().getPlugInInfos();

			for (PlugInInfo plugInInfo : plugInInfos) {
				log.debug("PlugIn name : " + plugInException.getPlugInName());
				
				if (plugInException.getPlugInName().equals(plugInInfo.getName())) {
					return MapUtils.getBoolean(plugInInfo.getParams(), "failOnExit", false);
				}

			}
		}
		
		return false;
	}		

	/**
	 * {@link ConfigurationLoader}를 소멸시킨다.
	 * 
	 * @param event ServletContextEvent
	 */
	public void contextDestroyed(ServletContextEvent event) {
		configurationLoader.destroy();
	}

	/**
	 * return filename of internal-configurations.
	 * 
	 * @return String[]
	 */
	private static String[] getInternalConfigurations() {
		String[] internalConfigurations = null;
		PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
		try {
			Resource[] resources = resolver.getResources("classpath*:META-INF/internal-usfconfig-*.xml");
			
			if (resources.length > 0) {
				internalConfigurations = new String[resources.length];
				int idx = 0;
				
				for (Resource resource : resources) {
					String filename = "META-INF/" + resource.getFilename();
					internalConfigurations[idx++] = filename;
					log.debug("extract internal usf-configuration : " + filename + " from " + resource.toString());
				}
			}
		} catch (IOException except) {
			log.error("Failure in finding internal-usf-configuration", except);
		}
		return internalConfigurations;
	}
}